home *** CD-ROM | disk | FTP | other *** search
/ The Utilities Experience / The Utilities Experience - Volume 1.iso / software / misc / o-z / x-windows / gs262 / gscoord.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-11-30  |  9.5 KB  |  349 lines

  1. /* Copyright (C) 1989, 1992 Aladdin Enterprises.  All rights reserved.
  2.  
  3. This file is part of Ghostscript.
  4.  
  5. Ghostscript is distributed in the hope that it will be useful, but
  6. WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
  7. to anyone for the consequences of using it or for whether it serves any
  8. particular purpose or works at all, unless he says so in writing.  Refer
  9. to the Ghostscript General Public License for full details.
  10.  
  11. Everyone is granted permission to copy, modify and redistribute
  12. Ghostscript, but only under the conditions described in the Ghostscript
  13. General Public License.  A copy of this license is supposed to have been
  14. given to you along with Ghostscript so you can know your rights and
  15. responsibilities.  It should be in a file named COPYING.  Among other
  16. things, the copyright notice and this notice must be preserved on all
  17. copies.  */
  18.  
  19. /* gscoord.c */
  20. /* Coordinate system operators for Ghostscript library */
  21. #include "math_.h"
  22. #include "gx.h"
  23. #include "gserrors.h"
  24. #include "gsccode.h"            /* for gxfont.h */
  25. #include "gxarith.h"
  26. #include "gxfixed.h"
  27. #include "gxmatrix.h"
  28. #include "gxfont.h"            /* for char_tm */
  29. #include "gzstate.h"
  30. #include "gzdevice.h"            /* requires gsstate */
  31. #include "gscoord.h"            /* requires gsmatrix, gsstate */
  32.  
  33. /* Choose whether to enable the new rounding code in update_ctm_fixed. */
  34. /* I'm pretty sure this is the right thing to do, but since this change */
  35. /* is being made 1 day before releasing version 2.4, I'm feeling cautious. */
  36. #define round_ctm_fixed 1
  37.  
  38. /* Forward declarations */
  39. #ifdef DEBUG
  40. private void trace_ctm(P1(const gs_state *));
  41. private void trace_matrix(P1(const gs_matrix *));
  42. #endif
  43. #ifdef AMIGA
  44. typedef struct gx_path_s gx_path;
  45. extern int gx_path_translate(gx_path *, fixed, fixed);
  46. #endif
  47.  
  48. /* Macro for ensuring ctm_inverse is valid */
  49. #ifdef DEBUG
  50. #define print_inverse(pgs)\
  51. if ( gs_debug['x'] )\
  52.     dprintf("[x]Inverting:\n"), trace_ctm(pgs), trace_matrix(&pgs->ctm_inverse)
  53. #else
  54. #define print_inverse(pgs) 0
  55. #endif
  56. #define ensure_inverse_valid(pgs)\
  57.     if ( !pgs->inverse_valid )\
  58.        {    int code = ctm_set_inverse(pgs);\
  59.         if ( code < 0 ) return code;\
  60.        }
  61.  
  62. private int
  63. ctm_set_inverse(gs_state *pgs)
  64. {    int code = gs_matrix_invert(&ctm_only(pgs), &pgs->ctm_inverse);
  65.     print_inverse(pgs);
  66.     if ( code < 0 ) return code;
  67.     pgs->inverse_valid = 1;
  68.     return 0;
  69. }
  70.  
  71. /* Machinery for updating fixed version of ctm. */
  72. /*
  73.  * We (conditionally) adjust the floating point translation
  74.  * so that it exactly matches the (rounded) fixed translation.
  75.  * This avoids certain unpleasant rounding anomalies, such as
  76.  * 0 0 moveto currentpoint not returning 0 0, and () stringwidth
  77.  * not returning 0 0.
  78.  */
  79. #if round_ctm_fixed            /* ****** NOTA BENE ****** */
  80. #  define update_t_fixed(mat, t, t_fixed)\
  81.     (mat).t = fixed2float((mat).t_fixed = float2fixed((mat).t))
  82. #else                    /* !round_update_fixed */
  83. #  define update_t_fixed(mat, t, t_fixed)\
  84.     (mat).t_fixed = float2fixed((mat).t)
  85. #endif                    /* (!)round_update_fixed */
  86. #define update_matrix_fixed(mat)\
  87.   update_t_fixed(mat, tx, tx_fixed),\
  88.   update_t_fixed(mat, ty, ty_fixed)
  89. #define update_ctm(pgs)\
  90.   update_matrix_fixed(pgs->ctm),\
  91.   pgs->inverse_valid = 0,\
  92.   pgs->char_tm_valid = 0
  93.  
  94. void
  95. gs_update_matrix_fixed(gs_matrix_fixed *pmat)
  96. {    update_matrix_fixed(*pmat);
  97. }
  98.  
  99. /* ------ Coordinate system definition ------ */
  100.  
  101. int
  102. gs_initmatrix(gs_state *pgs)
  103. {    gx_device *dev = pgs->device->info;
  104.     (*dev->procs->get_initial_matrix)(dev, &ctm_only(pgs));
  105.     update_ctm(pgs);
  106. #ifdef DEBUG
  107. if ( gs_debug['x'] )
  108.     dprintf("[x]initmatrix:\n"), trace_ctm(pgs);
  109. #endif
  110.     return 0;
  111. }
  112.  
  113. int
  114. gs_defaultmatrix(const gs_state *pgs, gs_matrix *pmat)
  115. {    gx_device *dev = pgs->device->info;
  116.     (*dev->procs->get_initial_matrix)(dev, pmat);
  117.     return 0;
  118. }
  119.  
  120. int
  121. gs_currentmatrix(const gs_state *pgs, gs_matrix *pmat)
  122. {    *pmat = ctm_only(pgs);
  123.     return 0;
  124. }
  125.  
  126. /* Read (after possibly computing) the current transformation matrix */
  127. /* for rendering text.  If force=1, update char_tm if it is invalid; */
  128. /* if force=0, don't update char_tm, and return an error code. */
  129. int
  130. gs_currentcharmatrix(gs_state *pgs, gs_matrix *ptm, int force)
  131. {    if ( !pgs->char_tm_valid )
  132.     {    int code;
  133.         if ( !force )
  134.             return gs_error_undefinedresult;
  135.         /* Compute combined transformation */
  136.         gs_make_identity(&char_tm_only(pgs));    /* make sure type */
  137.                     /* fields are set in char_tm! */
  138.         code = gs_matrix_multiply(&pgs->font->FontMatrix,
  139.                       &ctm_only(pgs), &char_tm_only(pgs));
  140.         if ( code < 0 )
  141.             return code;
  142.         gs_update_matrix_fixed(&pgs->char_tm);
  143.         pgs->char_tm_valid = 1;
  144.     }
  145.     if ( ptm != NULL )
  146.         *ptm = char_tm_only(pgs);
  147.     return 0;
  148. }
  149.  
  150. int
  151. gs_setmatrix(gs_state *pgs, const gs_matrix *pmat)
  152. {    ctm_only(pgs) = *pmat;
  153.     update_ctm(pgs);
  154. #ifdef DEBUG
  155. if ( gs_debug['x'] )
  156.     dprintf("[x]setmatrix:\n"), trace_ctm(pgs);
  157. #endif
  158.     return 0;
  159. }
  160.  
  161. int
  162. gs_translate(gs_state *pgs, floatp dx, floatp dy)
  163. {    gs_point pt;
  164.     int code;
  165.     if ( (code = gs_distance_transform(dx, dy, &ctm_only(pgs), &pt)) < 0 )
  166.         return code;
  167.     pgs->ctm.tx += pt.x;
  168.     pgs->ctm.ty += pt.y;
  169.     update_ctm(pgs);
  170. #ifdef DEBUG
  171. if ( gs_debug['x'] )
  172.     dprintf4("[x]translate: %f %f -> %f %f\n",
  173.          dx, dy, pt.x, pt.y),
  174.     trace_ctm(pgs);
  175. #endif
  176.     return 0;
  177. }
  178.  
  179. int
  180. gs_scale(gs_state *pgs, floatp sx, floatp sy)
  181. {    pgs->ctm.xx *= sx;
  182.     pgs->ctm.xy *= sx;
  183.     pgs->ctm.yx *= sy;
  184.     pgs->ctm.yy *= sy;
  185.     pgs->inverse_valid = 0, pgs->char_tm_valid = 0;
  186. #ifdef DEBUG
  187. if ( gs_debug['x'] )
  188.     dprintf2("[x]scale: %f %f\n", sx, sy), trace_ctm(pgs);
  189. #endif
  190.     return 0;
  191. }
  192.  
  193. int
  194. gs_rotate(gs_state *pgs, floatp ang)
  195. {    int code = gs_matrix_rotate(&ctm_only(pgs), ang, &ctm_only(pgs));
  196.     pgs->inverse_valid = 0, pgs->char_tm_valid = 0;
  197. #ifdef DEBUG
  198. if ( gs_debug['x'] )
  199.     dprintf1("[x]rotate: %f\n", ang), trace_ctm(pgs);
  200. #endif
  201.     return code;
  202. }
  203.  
  204. int
  205. gs_concat(gs_state *pgs, const gs_matrix *pmat)
  206. {    int code = gs_matrix_multiply(pmat, &ctm_only(pgs), &ctm_only(pgs));
  207.     update_ctm(pgs);
  208. #ifdef DEBUG
  209. if ( gs_debug['x'] )
  210.     dprintf("[x]concat:\n"), trace_matrix(pmat), trace_ctm(pgs);
  211. #endif
  212.     return code;
  213. }
  214.  
  215. /* ------ Coordinate transformation ------ */
  216.  
  217. int
  218. gs_transform(gs_state *pgs, floatp x, floatp y, gs_point *pt)
  219. {    return gs_point_transform(x, y, &ctm_only(pgs), pt);
  220. }
  221.  
  222. int
  223. gs_dtransform(gs_state *pgs, floatp dx, floatp dy, gs_point *pt)
  224. {    return gs_distance_transform(dx, dy, &ctm_only(pgs), pt);
  225. }
  226.  
  227. int
  228. gs_itransform(const gs_state *pgs, floatp x, floatp y, gs_point *pt)
  229. {    /* If the matrix isn't skewed, we get more accurate results */
  230.     /* by using transform_inverse than by using the inverse matrix. */
  231.     if ( !is_skewed(&pgs->ctm) )
  232.        {    return gs_point_transform_inverse(x, y, &ctm_only(pgs), pt);
  233.        }
  234.     else
  235.        {    ensure_inverse_valid(pgs);
  236.         return gs_point_transform(x, y, &pgs->ctm_inverse, pt);
  237.        }
  238. }
  239.  
  240. int
  241. gs_idtransform(gs_state *pgs, floatp dx, floatp dy, gs_point *pt)
  242. {    /* If the matrix isn't skewed, we get more accurate results */
  243.     /* by using transform_inverse than by using the inverse matrix. */
  244.     if ( !is_skewed(&pgs->ctm) )
  245.        {    return gs_distance_transform_inverse(dx, dy,
  246.                              &ctm_only(pgs), pt);
  247.        }
  248.     else
  249.        {    ensure_inverse_valid(pgs);
  250.         return gs_distance_transform(dx, dy, &pgs->ctm_inverse, pt);
  251.        }
  252. }
  253.  
  254. /* ------ For internal use only ------ */
  255.  
  256. /* Set the translation to a fixed value, */
  257. /* translate any existing path, and mark char_tm as valid. */
  258. /* Used by gschar.c to prepare for a BuildChar or BuildGlyph procedure. */
  259. int
  260. gs_translate_to_fixed(register gs_state *pgs, fixed px, fixed py)
  261. {    fixed dx = px - pgs->ctm.tx_fixed;
  262.     fixed dy = py - pgs->ctm.ty_fixed;
  263.     gx_path_translate(pgs->path, dx, dy);
  264.     pgs->ctm.tx = fixed2float(pgs->ctm.tx_fixed = px);
  265.     pgs->ctm.ty = fixed2float(pgs->ctm.ty_fixed = py);
  266.     pgs->inverse_valid = 0;
  267.     pgs->char_tm_valid = 1;
  268.     return 0;
  269. }
  270.  
  271. /* Compute the coefficients for fast fixed-point distance transformations */
  272. /* from a transformation matrix. */
  273. /* We should cache the coefficients with the ctm.... */
  274. int
  275. gx_matrix_to_fixed_coeff(const gs_matrix *pmat, register fixed_coeff *pfc,
  276.   int max_bits)
  277. {    gs_matrix ctm;
  278.     int scale = -10000;
  279.     int expt, shift;
  280.     ctm = *pmat;
  281.     pfc->skewed = 0;
  282.     if ( !is_fzero(ctm.xx) )
  283.        {    (void)frexp(ctm.xx, &scale);
  284.        }
  285.     if ( !is_fzero(ctm.xy) )
  286.        {    (void)frexp(ctm.xy, &expt);
  287.         if ( expt > scale ) scale = expt;
  288.         pfc->skewed = 1;
  289.        }
  290.     if ( !is_fzero(ctm.yx) )
  291.        {    (void)frexp(ctm.yx, &expt);
  292.         if ( expt > scale ) scale = expt;
  293.         pfc->skewed = 1;
  294.        }
  295.     if ( !is_fzero(ctm.yy) )
  296.        {    (void)frexp(ctm.yy, &expt);
  297.         if ( expt > scale ) scale = expt;
  298.        }
  299.     scale = sizeof(long) * 8 - 1 - max_bits - scale;
  300.     shift = scale - _fixed_shift;
  301.     if ( shift > 0 )
  302.        {    pfc->shift = shift;
  303.         pfc->round = (fixed)1 << (shift - 1);
  304.        }
  305.     else
  306.        {    pfc->shift = 0;
  307.         pfc->round = 0;
  308.         scale -= shift;
  309.        }
  310. #define set_c(c)\
  311.   if ( is_fzero(ctm.c) ) pfc->c.f = 0, pfc->c.l = 0;\
  312.   else pfc->c.f = ldexp(ctm.c, _fixed_shift), pfc->c.l = (long)ldexp(ctm.c, scale)
  313.     set_c(xx);
  314.     set_c(xy);
  315.     set_c(yx);
  316.     set_c(yy);
  317. #ifdef DEBUG
  318. if ( gs_debug['x'] )
  319.    {    dprintf7("[x]ctm: [%6g %6g %6g %6g ; %6g %6g] scale=%d\n",
  320.          ctm.xx, ctm.xy, ctm.yx, ctm.yy, ctm.tx, ctm.ty, scale);
  321.     dprintf5("   fc: [%lx %lx %lx %lx] shift=%d\n",
  322.          pfc->xx, pfc->xy, pfc->yx, pfc->yy,
  323.          pfc->shift);
  324.    }
  325. #endif
  326.     pfc->max_bits = max_bits;
  327.     return 0;
  328. }
  329.  
  330. /* ------ Debugging printout ------ */
  331.  
  332. #ifdef DEBUG
  333.  
  334. /* Print a matrix */
  335. private void
  336. trace_ctm(const gs_state *pgs)
  337. {    const gs_matrix_fixed *pmat = &pgs->ctm;
  338.     trace_matrix((gs_matrix *)pmat);
  339.     dprintf2("\t\tt_fixed: [%6g %6g]\n",
  340.          fixed2float(pmat->tx_fixed), fixed2float(pmat->ty_fixed));
  341. }
  342. private void
  343. trace_matrix(register const gs_matrix *pmat)
  344. {    dprintf6("\t[%6g %6g %6g %6g %6g %6g]\n",
  345.          pmat->xx, pmat->xy, pmat->yx, pmat->yy, pmat->tx, pmat->ty);
  346. }
  347.  
  348. #endif
  349.